package com.yehun.config;

import com.yehun.enums.BaseEnum;
import com.yehun.utils.Constant;
import org.apache.ibatis.type.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

/**
 * mybatis枚举类型处理
 * org.apache.ibatis.type.EnumOrdinalTypeHandler
 * org.apache.ibatis.type.EnumTypeHandler
 * Created by Genius on 2017/4/13 0013.
 */
@MappedJdbcTypes(value = { JdbcType.NUMERIC, JdbcType.INTEGER })
public class EnumTypeHandler<E extends Enum<?> & BaseEnum<Integer>> extends BaseTypeHandler<BaseEnum<Integer>> {

    private static final Logger logger = LoggerFactory.getLogger(EnumTypeHandler.class);

    private Class<E> type;

    public EnumTypeHandler() { }

    /**
     * 设置配置文件设置的转换类以及枚举类内容
     * @param type 配置文件中设置的转换类
     */
    public EnumTypeHandler(Class<E> type) {
        if (type == null)
            throw new IllegalArgumentException("Type argument cannot be null");
        this.type = type;
    }

    @Override
    public void setNonNullParameter(PreparedStatement ps, int i, BaseEnum<Integer> parameter, JdbcType jdbcType) throws SQLException {
        if (jdbcType == null) {
            Object id = parameter.getValue();
            if (id instanceof Integer || id instanceof Short || id instanceof Character || id instanceof Byte) {
                ps.setInt(i, (Integer) id);
            } else if (id instanceof String) {
                ps.setString(i, (String) id);
            } else if (id instanceof Boolean) {
                ps.setBoolean(i, (Boolean) id);
            } else if (id instanceof Long) {
                ps.setLong(i, (Long) id);
            } else if (id instanceof Double) {
                ps.setDouble(i, (Double) id);
            } else if (id instanceof Float) {
                ps.setFloat(i, (Float) id);
            } else {
                throw new RuntimeException("unsupported [id] type of enum");
            }
        } else {
            ps.setObject(i, parameter.getValue(), jdbcType.TYPE_CODE); // see r3589
        }
    }

    @Override
    public E getNullableResult(ResultSet rs, String columnName) throws SQLException {
        Integer i = rs.getInt(columnName);
        return rs.wasNull() ? null : getEnum(i);
    }

    @Override
    public E getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
        Integer i = rs.getInt(columnIndex);
        return rs.wasNull() ? null : getEnum(i);
    }

    @Override
    public E getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
        Integer i = cs.getInt(columnIndex);
        return cs.wasNull() ? null : getEnum(i);
    }

    /**
     * 枚举类型转换，由于构造函数获取了枚举的子类enums
     *
     * @param value 数据库中存储的自定义value属性
     * @return value对应的枚举类
     */
    private E getEnum(Integer value) {
        //logger.debug("---------------------------------------------" + type.getName());
        E[] enums = this.type.getEnumConstants();
        if(enums != null) {
            for (E e : enums) {
                if (e.getValue().equals(value)) {
                    //logger.debug("---------------------------------------------" + e.getText());
                    return e;
                }
            }
        }
        throw new IllegalArgumentException("未知的枚举类型：" + value + ",请核对" + type.getSimpleName());

    }
}
